package core.reports;

import java.util.*;

import common.util.DateUtils;

import core.*;

public class OracleForProdStatReport 
{
	Calendar _startReport;
	Calendar _startProd;
	Calendar _end;
	Product _prod;
	ItemManager _iMgr;
	ItemFacade _iFacade;
	
	float _supplyAvg;
	int _supplyMin;
	int _supplyMax;
	int _supplyUsed;
	int _supplyAdded;
	float _usedAgeAvg;
	int _usedAgeMax;
	float _currAgeAvg;
	int _currAgeMax;
	
	public OracleForProdStatReport(Product prod, Calendar start, Calendar end)
	{
		_prod = prod;
		_startReport = start;
		DateUtils.setToMidnight(_startReport);
		_end = end;
		DateUtils.setToMidnight(_end);
		_iMgr = ItemManager.instance();
		_iFacade = ItemFacade.instance();
		calculateStartForProduct(start);
		DateUtils.setToMidnight(_startProd);
		calculateSupplyNumbers();
		calculateUsedNumbers();
	}

	private void calculateStartForProduct(Calendar start) 
	{
		Iterator<Item> iterItem= _iMgr.getAllItemsInProduct(_prod);
		
		if (iterItem == null)
		{
			_startProd = start;
			return;
		}
		
		_startProd = Calendar.getInstance();
		while (iterItem.hasNext())
		{
			Item item = iterItem.next();
			if (item.getEntryDate().before(_startProd))
			{
				_startProd = item.getEntryDate();
			}
		}
		
		if (_startProd.before(start))
			_startProd = start;
	}

	public int getCurrentSupply()
	{
		return _iFacade.getNumberOfItemsInProduct(_prod.getBarcode().toString());
	}
	
	public float getSupplyAvg()
	{
		return _supplyAvg;
	}
	
	public int getSupplyMin()
	{
		return _supplyMin;
	}
	
	public int getSupplyMax()
	{
		return _supplyMax;
	}
	
	public int getSupplyUsed()
	{
		return _supplyUsed;
	}
	
	public int getSupplyAdded()
	{
		return _supplyAdded;
	}
	
	public float getUsedAvg()
	{
		return _usedAgeAvg;
	}
	
	public int getUsedMax()
	{
		return _usedAgeMax;
	}
	
	public float getCurrAvg()
	{
		return _currAgeAvg;
	}
	
	public int getCurrMax()
	{
		return _currAgeMax;
	}
	private void calculateSupplyNumbers()
	{
		calcSupplyAvgMinMax();
		calcSupplyUsedAdded();
	}

	private void calcSupplyUsedAdded() 
	{
		int added = 0;
		int used = 0;

		Iterator<Item> iterItem= _iMgr.getAllItemsInProduct(_prod);
		if (iterItem == null)
			return;

		while (iterItem.hasNext())
		{
			Item tempItem = iterItem.next();

			Calendar start = (Calendar)_startReport.clone();
			DateUtils.setToMidnight(start);
			
			Calendar entry = (Calendar)tempItem.getEntryDate().clone();
			DateUtils.setToMidnight(entry);
			
			if (!entry.before(start))
				added++;
			if (tempItem.isUsed())
			{
				Calendar exit = (Calendar)tempItem.getExitDate().clone();
				DateUtils.setToMidnight(exit);
				if (!exit.before(start))
					used++;
			}
		}
		_supplyUsed = used;
		_supplyAdded = added;
	}

	private void calcSupplyAvgMinMax() 
	{
		ArrayList<Integer> numPerDay = new ArrayList<Integer>();
		int daysInReport = DateUtils.daysBetweenInclusive(_startProd, _end);
		for (int i = 0; i < daysInReport; i++)
		{
			numPerDay.add(0);
		}

		Iterator<Item> iterItem= _iMgr.getAllItemsInProduct(_prod);
		if (iterItem == null)
			return;

		while (iterItem.hasNext())
		{
			Item tempItem = iterItem.next();
			int index = 0;
			for (Integer i: numPerDay)
			{
				Calendar tempCal = (Calendar)_startProd.clone();
				DateUtils.setToMidnight(tempCal);
				tempCal.add(Calendar.DAY_OF_MONTH, index);
				if (tempItem.existedOnDate(tempCal))
				{
					numPerDay.set(index, numPerDay.get(index) + 1);
				}
				if (tempItem.isUsed())
				{
					Calendar used = tempItem.getExitDate();
					DateUtils.setToMidnight(used);
					if (used.equals(tempCal))
						numPerDay.set(index, numPerDay.get(index) - 1);
				}
				index++;
			}
		}
		int sum = 0;
		_supplyMin = -1;
		for (int i: numPerDay)
		{
			sum += i;
			if (_supplyMin == -1)
			{
				_supplyMin = i;
			}
			if (_supplyMin > i)
				_supplyMin = i;
			if (_supplyMax < i)
				_supplyMax = i;
		}
		_supplyAvg = (float)sum/numPerDay.size();
	}
	
	private void calculateUsedNumbers() 
	{
		Iterator<Item> iterItem= _iMgr.getAllItemsInProduct(_prod);
		if (iterItem == null)
			return;
		
		int usedSum = 0;
		int usedCount = 0;
		int currSum = 0;
		int currCount = 0;
		_usedAgeMax = 0;
		_currAgeMax = 0;
		while (iterItem.hasNext())
		{
			Item item = iterItem.next();
			Calendar entered = item.getEntryDate();
			DateUtils.setToMidnight(entered);
			if (item.isUsed())
			{
				Calendar used = (Calendar)item.getExitDate().clone();
				DateUtils.setToMidnight(used);
				int age = DateUtils.daysBetween(entered, used);
				
				if (!used.before(_startReport))
				{
					usedCount++;
					usedSum += age;
					if (age > _usedAgeMax)
						_usedAgeMax = age;
				}
			}
			else
			{
				int age = DateUtils.daysBetween(entered, _end);
				currCount++;
				currSum += age;
				if (age > _currAgeMax)
					_currAgeMax = age;
			}
		}
		if (currCount == 0)
			_currAgeAvg = 0;
		else
			_currAgeAvg = (float)currSum/currCount;
		
		if (usedCount == 0)
			_usedAgeAvg = 0;
		else
			_usedAgeAvg = (float)usedSum/usedCount;
	}
}
